#define _GNU_SOURCE
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <inttypes.h>
#include <linux/if_link.h>
#include <netdb.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <math.h>
#include <openssl/hmac.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>

// static const unsigned char base64_enc_map[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
// 						  'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
// 						  's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
static const unsigned char base64_enc_map[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
						  'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
						  's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' };
static const unsigned char base64_dec_map[128] = { 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
						   127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 62,  127, 127, 127, 63,	 52,  53,  54,	55,
						   56,	57,  58,  59,  60,  61,	 127, 127, 127, 64,  127, 127, 127, 0,	 1,   2,   3,	4,   5,	  6,   7,   8,	 9,   10,  11,	12,
						   13,	14,  15,  16,  17,  18,	 19,  20,  21,	22,  23,  24,  25,  127, 127, 127, 127, 127, 127, 26,  27,  28,	 29,  30,  31,	32,
						   33,	34,  35,  36,  37,  38,	 39,  40,  41,	42,  43,  44,  45,  46,	 47,  48,  49,	50,  51,  127, 127, 127, 127, 127 };
#define BASE64_SIZE_T_MAX ((size_t)-1) /* SIZE_T_MAX is not standard */
/*
 * Encode a buffer into base64 format
 */
int mbedtls_base64_encode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen)
{
	size_t i, n;
	int C1, C2, C3;
	unsigned char *p;
	if (slen == 0) {
		*olen = 0;
		return (0);
	}
	n = slen / 3 + (slen % 3 != 0);
	if (n > (BASE64_SIZE_T_MAX - 1) / 4) {
		*olen = BASE64_SIZE_T_MAX;
		return (-1);
	}
	n *= 4;
	if ((dlen < n + 1) || (NULL == dst)) {
		*olen = n + 1;
		return (-1);
	}
	n = (slen / 3) * 3;
	for (i = 0, p = dst; i < n; i += 3) {
		C1 = *src++;
		C2 = *src++;
		C3 = *src++;
		*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
		*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
		*p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
		*p++ = base64_enc_map[C3 & 0x3F];
	}
	if (i < slen) {
		C1 = *src++;
		C2 = ((i + 1) < slen) ? *src++ : 0;
		*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
		*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
		if ((i + 1) < slen)
			*p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
		else
			*p++ = '=';
		*p++ = '=';
	}
	*olen = p - dst;
	*p = 0;
	return (0);
}

const char *ak = "qiniu";
const char *sk = "qiniu";

int main()
{
	const unsigned char data[] = "austin";
	unsigned char result[1024];
	uint32_t len;
	HMAC_CTX *hmac = HMAC_CTX_new();
	const EVP_MD *md = EVP_sha1();
	HMAC_Init_ex(hmac, sk, strlen(sk), md, NULL);

	HMAC_Update(hmac, data, strlen((const char *)data));
	HMAC_Final(hmac, result, &len);
	HMAC_CTX_free(hmac);

	char signresult[1024];
	size_t rlen = 0;
	mbedtls_base64_encode((void *)signresult, sizeof(signresult), &rlen, result, len);
	signresult[rlen] = 0;

	printf("rlen=%u result:=%s\n", rlen, signresult);

	return 0;
}